package com.xiaolong.log.aspectj;

import com.alibaba.fastjson2.JSON;
import com.xiaolong.common.context.ApplicationContext;
import com.xiaolong.common.context.UserInfo;
import com.xiaolong.log.annotation.Log;
import com.xiaolong.log.enums.StatusEnum;
import com.xiaolong.log.msg.LogMessage;
import com.xiaolong.log.util.HttpUtil;
import com.xiaolong.log.util.InstanceUtil;
import com.xiaolong.log.util.LogUtil;
import com.xiaolong.log.util.SendUtil;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;
import java.util.Objects;

@Aspect
public class LogAspect {

    private Logger log = LoggerFactory.getLogger(this.getClass());


    @Pointcut("(@within(org.springframework.web.bind.annotation.RestController) || " +
            "@within(org.springframework.stereotype.Controller)) && " +
            "@annotation(com.xiaolong.log.annotation.Log)")
    public void logPointCut() {
    }

    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        LogMessage message = initLogMessage(point);
        try {
            Object result = point.proceed();
            message.setEndTime(System.currentTimeMillis());
            message.setStatus(StatusEnum.SUCCESS.ordinal());
            message.setRespParam(JSON.toJSONString(result));
            SendUtil.sendLog(message);
            return result;
        } catch (Throwable e) {
            message.setEndTime(System.currentTimeMillis());
            message.setStatus(StatusEnum.FAIL.ordinal());
            message.setRemark(LogUtil.getStackTrace(e));
            SendUtil.sendLog(message);
            throw e;
        }
    }



    public LogMessage initLogMessage(ProceedingJoinPoint point) {
        LogMessage message = new LogMessage();
        message.setStartTime(System.currentTimeMillis());
        //sysInfo
        handlerSysInfo(message);
        //http
        handlerHttpRequest(message);
        //method
        Method method = handlerMethod(point, message);
        //user
        handlerUserInfo(message);
        //loginfo
        handlerLogInfo(method, message);
        return message;
    }

    private void handlerSysInfo(LogMessage message) {
        message.setInstanceIp(InstanceUtil.instanceIp());
        message.setInstanceName(InstanceUtil.instanceName());
        message.setInstancePort(InstanceUtil.instancePort());
    }

    private static void handlerLogInfo(Method method, LogMessage message) {
        Log logInfo = method.getAnnotation(Log.class);
        message.setModule(logInfo.module());
        message.setTopic(logInfo.topic().ordinal());
        message.setPlatform(logInfo.platform().ordinal());
        message.setType(logInfo.logType().ordinal());
    }

    private Method handlerMethod(ProceedingJoinPoint point, LogMessage message) {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        message.setClassName(point.getTarget().getClass().getSimpleName());
        message.setMethodName(method.getName());
        message.setRequestParam(LogUtil.getRequestParam(point));
        return method;
    }

    private static void handlerUserInfo(LogMessage message) {
        Long userId = 0L;
        String userName = "非系统用户访问";
        UserInfo user = ApplicationContext.getUser();
        if (!Objects.isNull(user)) {
            userId = user.getUserId();
            userName = user.getUserName();
        }
        message.setUserId(userId);
        message.setUserName(userName);
    }

    private void handlerHttpRequest(LogMessage message) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        message.setHttpMethod(HttpUtil.method(request));
        message.setHttpUrl(HttpUtil.url(request));
        message.setIp(HttpUtil.ip(request));
    }






}
